#!/bin/bash
#THIS DRIVER WRITTEN BY MATTHEW VONA ARB FOR API 400A
#FOR QUESTIONS WRITE mailto:mvona@arb.ca.gov
#UPDATE 7/28/2009 for file locking, awk variable passing, etc
#ALSO UPDATED GETOPTS TO ACCEPT LIMITS
#-------------------------------------------------------------
#!/usr/bin/env bash
# THIS IS THE FUNCTION CALLED IN THE EVENT THAT CTRL+C IS PRESSED
cleanup()
{
	echo "Caught Signal ... cleaning up."
	echo "Done cleanup ... quitting."
	exit 1
}
#THE DIAGNOSTIC DATA (DIAG) ROUTINE TAKES THE DATA STREAM FROM THE API 400A
#AND TESTS FOR THE RECOGNITION OF KEY WORDS IN EACH LINE OF OUTPUT.
#IF THE KEY WORD IS DETECTED ON THAT LINE, A TEST IS PERFORMED. 
#IF THE TEST SUGGESTS THAT AN ERROR CONDITION EXISTS BASED UPON THE ALLOWABLE
#RANGES SPECIFIED BY THE ARB CHECKSHEET, THE OFFENDING LINE IS WRITTEN OUT 
#TO A FILE IN THE Data DIRECTORY. THE NAME OF THE DESTINATION FILE IS
#errors{HH}. THE FILES CAN THEN BE PARSED AND UTILIZED BY ANY ALERT PROGRAM?DAEMON.
diag()
{
thishour=`date "+%H"`
thisalert="errors$thishour"
while read DIAGS
do
awk -v upp_flow=${upp_flow} -v low_flow=${low_flow} -v izs=${izs_val} '
{
# TEST FOR ANY WARNING MESSAGES
if ($6 ~ /WARN/)
	{
	print
	}
# TEST THE TIME AGAINST DATA LOGGER
if ($4 ~ /TIME=/)
{
#do not run this test during the first or last three minutes of any hour
	if (substr($4,9,2) == 20)
	{
	#test for off an hour or more
		if (substr($4,6,2) != substr($1,length($1)-8,2))
  			{ print }
	#test for off more than 2 minutes. Must add one minute to the 
	#current minute value since the buffer contains values from the previous minute
	  	if (sqrt(((substr($4,9,2)+1) - substr($1,length($1)-5,2))^2) > 3 )
  		{ print }	
	}
}
# TEST THE RANGE
if ($4 ~ /RANGE=/ ) 
	{
 	if (substr($4,7) !~ 500.0)
  		{ print }
	}

# TEST THE FLOW RATE
if ($5 ~ /FL=/ ) 
	{
 	if (substr($5,4)<=low_flow)
  		{ print }
  	if (substr($5,4)>=upp_flow)
  		{ print }	
  	if (substr($5,4) ~ /XXXX/)
  		{ print }
	}
#TEST THE LAMP VOLTAGE
if ($5 ~ /LAMP=/)
	{
	if (substr ($5,6)>=52.5)
		{ print }
	if (substr ($5,6)<=51.5)
		{ print }
	}
#TEST THE DCPS
if ($4 ~ /DCPS=/)
	{
	if (substr ($4,6)>= 2600)
		{ print }
	if (substr ($4,6)<= 2400)
		{ print }
	}
#TEST THE OFFSET
if ($4 ~ /OFFSET=/)
	{
	if (sqrt((substr ($4,8))^2)>= 5)
		{ print }	
	}	
	
#TEST THE O3 MEAS
if (/O3 MEAS=/)
	{
	if (substr ($5,6)<=2500)
		{ print }
	if (substr ($5,6)>=4900)
		{ print }
	}
#TEST THE SLOPE FOR 1 +/- .1 AND CHANGES
if (/SLOPE=/)
	{
		if (substr ($4,7) >= 1.1)
			{ print }
		if (substr ($4,7) <= .9)
			{ print }
	}
#THESE TESTS ARE RUN IF THE izs=on PARAMETER HAS BEEN PASSED
if (/O3 GEN TMP=/)
		{
		if (izs == on)
			{
			if (substr ($6,5)<=47.5)
				{ print }
			if (substr ($6,5)>=48.5)
				{ print }
			}
		}
if (/O3 DRIVE=/)
		{
		if (izs == on)
			{
			if (substr ($5,7)<=0)
				{ print }
			if (substr ($5,7)>=5000)
				{ print }
			}
		}			
if (/O3 GEN=/)
		{
		if (izs == on)
			{
			if (substr ($5,5)<=0)
				{ print }
			if (substr ($5,5)>=5000)
				{ print }
			}
		}
}' >> "../../Data/$thisalert"
done
}
#BEGIN WRITE
#THIS FUNCTION HANDELS READ RIGHT HANDSHAKES BETWEEN VARIOUS DRIVERS
#IN GENERAL, THE DATA IS PLACED IN THE VARIABLE $TIMESTAMP PRIOR TO CALL
#NEXT, IT OPENS THE DATA DIRECTORY AND LOOKS FOR THE .locked FILE
#IF IT EXISTS, IT HANGS OUT UNTIL IT DOESNt EXIST. AT THAT POINT
#IT CREATES A .locked FILE, AND APPENDS TO THE DATA RECORD.
#FINALLY IT REMOVES THE .locked FILE IT HAS CREATED.
#written by MJV
write()
{
#CONFIRM THAT THERE IS NO HIDDEN FILE CALLED '.locked'
	while [ -e "../../Data/.locked" ];
		do
			sleep .2;
		done	
	echo "LOCKED" > "../../Data/.locked";
	if !(echo "$data" | sed 's/^/'$timestamp'/g'| tee -a "../../Data/$datafile" | diag ); then
		{
			echo "GENERAL FAILURE WRITING TO RECORD: $#";
			exit 1;
		}
	fi
	if !(rm "../../Data/.locked"); then
		{
			echo "GENERAL FAILURE REMOVING LOCK: $#";
			exit 1;	
		}
	fi
	if !(timestamp="" && data=""); then
		{
		echo "GENERAL FAILURE CLEARING WRITE BUFFER: $#";
		exit 1;
		}
	fi	
}

#THIS IS THE ACTUAL COMMUNICATION WITH THE INSTRUMENT
#THE TIMER CONTROL. AT THE BEGINING IT TESTS FOR THE 
#EXISTENCE IF TOGGLE VARRIABLES WHICH ARE UTILIZED BOTH BY
#THE COMM ROUTINE runit() AND THE DIAGNOSTICS DATA ROUTINE
#diag()

runit()
{
#IF THE -d, -C, or -p variable is set to on, then append those parameters
#to the sjinn communication string. If the -i parameter is passed, diag will
#test for IZS specific routines.
if [ "$izs_val" = "on" ]; then
	izs="on"
fi
if [ "$dtr_val" = "on" ]; then
 	dtr="--dtr" 
fi
if [ "$ctr_val" = "on" ]; then
 	ctr="--ctr"
fi
if [ "$p8n1_val" = "on" ]; then
 	p8n1="-p8n1"
fi
today=`date "+%Y-%d-%m"`
timestamp=$rprt_nm::`date "+%m-%d-%Y_%H:%M"`:::
#THIS IS THE NAME OF THE DATA FILE RIGHT NOW
datafile="$saroad-$today"
#TALK TO THE INSTRUMENT, PRE-APPEND THE TIMESTAMP AND REPORTING NAME TO EACH
#LINE OF OUTPUT AND tee TO THE DATA FILE, then pass to the diag routine.
data=`sjinn -b$bd_rt -d $dvc_prt -s "$cmnd1" -r$rsp_lngth -w$wt_rsp1 $p8n1 $dtr $ctr\
 | grep -v "^$"`
write
}
#THIS IS THE FUNCTION RUN IN THE EVENT THAT THE REQUIRED PARAMETERS
#ARE NOT ENTERED.
usage()
{
clear
cat << EOF
usage: $0 options
OPTIONS:
-h	display help
-i	Activate Diagnostics for IZS model [e.g. on, off] 
-r	rprt_nm [rn]
-d	dvc_prt [eg, /dev/ttyS0, /dev/ttyUSB1] 
-b	bd_rt [2400,4800,9600,etc.]
-c	cmnd1
-w	wt_rsp1 [seconds]
-l	rsp_lngth [characters]
-s	SAROAD number of the station
-a	absolute path to the data file directory
-t	[on/off] (OPTIONAL)
-C	[on/off] (OPTIONAL)
-p	[on/off] (OPTIONAL)
-o	display default options
-U upper flow rate limit
-L lower flow rate limit
UPDATED 7/28/2009
EOF
}
#HELP FUNCTION GIVES BACKGROUND ON THIS DRIVER
help_me ()
{
clear
cat .help
exit 0
}
def_opts ()
{
clear
cat .options
}

	##CLEAR ALL VARIABLES               
rprt_nm= ; dvc_prt= ; bd_rt= ; cmnd1= ; wt_rsp1= ; bd_rt= ; rsp_lngth= ; izs_val= ;
dvc_prt= ; frqncy= ; dtr= ; ctr= ; p8n1= ; izs= ; saroad= ; p8n1= ; low_flow=720 ; upp_flow=880 ;
abs_path=`pwd` ; timestamp= ; data= ;
##INITIALIZE THE BUFFER
return='NOT WRITTEN TO'

##loop through all variables and parameters
##Note that the position of the colon indicates the presence
##of a parameter to collect. The h parameter simply
##returns the help message.

while getopts “hi:r:a:s:d:b:c:w:l:f:t:C:p:U:L:” OPTION
do
case $OPTION in
U)
upp_flow=$OPTARG
;;
L)
low_flow=$OPTARG
;;
a)
abs_path=$OPTARG
;;
i)
izs_val=$OPTARG
;;
s)
saroad=$OPTARG
;;
r)
rprt_nm=$OPTARG
;;
d)
dvc_prt=$OPTARG
;;
b)
bd_rt=$OPTARG
;;
c)
cmnd1=$OPTARG
;;
w)
wt_rsp1=$OPTARG
;;
l)
rsp_lngth=$OPTARG
;;
f)
frqncy=$OPTARG
;;
t)
dtr_val=$OPTARG
;;
C)
ctr_val=$OPTARG
;;
p)
p8n1_val=$OPTARG
;;
h)
help_me
exit 1
;;
*)
usage
exit 1
;;
esac
done
#CHECK FOR THE CRITICAL PARAMETERS, IF THEY ARE NOT PRESENT THEN
#RUN THE USAGE FUNCTION WHICH RETURNS THE INSTRUCTIONS FOR PROPER USAGE
#MUST HAVE r d b c w l i s
if [ -z "$rprt_nm" ] || [ -z "$dvc_prt" ] || [ -z "$bd_rt" ] || [ -z "$cmnd1" ] ||
[ -z "$wt_rsp1" ] || [ -z "$rsp_lngth" ] || [ -z "$saroad" ] || [ -z "$izs_val" ]
	then
		{
		usage
		exit
		}
fi
	#INITIALIZED THE RAN VARIABLE. THIS IS USED TO TOGGLE THE TIMER GATE
ran=0
	#TRAP CTRL+C
trap cleanup 1 2 3 6 15
	#SETUP THE OPERATING LOOP
while :
do
	#SET THE SECOND VARIABLE AS-i off -r API400A_2 -d '/dev/ttyS0' -b9600 -c "T LIST ALL\\r" -w 4 -l 926 -s 34305 -p on -U 880 -L 720 THE SECOND VALUE FROM THE DATA STAMP 
second=`date "+%S"`
	#IF THE SECOND VALUE IS LESS THAN 02, BEGIN RUNNING
if [ "$second" -eq "00" ] && [ "$ran" -eq "0" ]; then
	{
	#RUN THE RUNIT FUNCTION
		runit
	#TOGGLE THE RAN VARIABLE SO THAT THE PROCESS WILL NOT REPEAT
	#UNTIL THE BEGINNING OF THE NEXT MINUTE.
		ran=1
	#WAIT FOR COMPLETION OF THE RUNIT FUNCTION AND THE VARIABLE
	#SET
		sleep 1
	}
	#IF THE SECOND VALUE IS GREATER THAT 02, RESET RAN TO 0
	#AND WAIT ONE SECOND BEFORE CHECKING AGAIN
else 
	{
	#WAIT ONE SECOND
		sleep .5
	#SET RAN TO 0
		ran=0
	}
fi
done;
exit;

